#include "pc.hpp"

auto const s_log_path = "/data/rts_test_logs/loss40/"s;

auto pre_html = R"(
<html>
<body>

<style>
table,table tr th, table tr td
{ 
    border:2px solid #ccc;
}
</style>

<table border="2px">
    <tr>
        <th>QPS 和消息长度</th>
        <th>网络 RTT</th>
		<th>PCT50</th>
		<th>PCT75</th>
		<th>PCT90</th>
		<th>PCT95</th>
		<th>PCT99</th>
		<th>PCT100</th>
    </tr>
)";

auto post_html = R"(
</table>

</body>
</html>
)";

int main()
{
    std::vector<int> qpses{1, 5, 10, 20, 50, 100, 200};
    std::vector<int> lengths{
        5, 500, 1000, 2000, 4000, 8000, 16000, 32000, 65000};

    auto s_html = std::string(pre_html);

    for (auto qps : qpses)
    {
        for (auto length : lengths)
        {
            auto const s_file_path = scat(s_log_path,
                                          "qps"sv,
                                          std::to_string(qps),
                                          "_"sv,
                                          std::to_string(length),
                                          ".txt"sv);

            auto fin  = std::ifstream(s_file_path);
            auto line = std::string{};

            auto fpts = std::vector<std::size_t>{};
            auto spts = std::vector<std::size_t>{};
            auto bpts = std::vector<std::size_t>{};
            auto e2es = std::vector<std::size_t>{};

            fpts.reserve(20000);
            spts.reserve(20000);
            bpts.reserve(20000);
            e2es.reserve(20000);

            while (std::getline(fin, line))
            {
                auto mr =
                    getMatchResults(line,
                                    rgx<R"(^[0-9]+\|.+\|([0-9]+)\|([0-9]+)\|)"
                                        R"(([0-9]+)\|([0-9]+)\|[\s\S]+$)">());
                if (mr.size() > 4)
                {
                    e2es.emplace_back(*ton(mr[1]));
                    fpts.emplace_back(*ton(mr[2]));
                    spts.emplace_back(*ton(mr[3]));
                    bpts.emplace_back(*ton(mr[4]));
                }
            }

            ::ranges::sort(fpts);
            ::ranges::sort(spts);
            ::ranges::sort(bpts);
            ::ranges::sort(e2es);

            auto const pct50_idx = e2es.size() * 50 / 100;
            auto const pct75_idx = e2es.size() * 75 / 100;
            auto const pct90_idx = e2es.size() * 90 / 100;
            auto const pct95_idx = e2es.size() * 95 / 100;
            auto const pct99_idx = e2es.size() * 99 / 100;

            xout(qps, " & "sv, length, " & "sv, e2es.size());

            s_html += "<tr>"sv;

            s_html += scat("<td>qps_"sv,
                           std::to_string(qps),
                           " & msg_len_"sv,
                           std::to_string(length),
                           "</td>"sv);

            s_html += "<td>75</td>";

            s_html += scat("<td>"sv,
                           std::to_string(fpts[pct50_idx]),
                           _I_,
                           std::to_string(spts[pct50_idx]),
                           _I_,
                           std::to_string(bpts[pct50_idx]),
                           _I_,
                           std::to_string(e2es[pct50_idx]),
                           "</td>"sv);
            s_html += scat("<td>"sv,
                           std::to_string(fpts[pct75_idx]),
                           _I_,
                           std::to_string(spts[pct75_idx]),
                           _I_,
                           std::to_string(bpts[pct75_idx]),
                           _I_,
                           std::to_string(e2es[pct75_idx]),
                           "</td>"sv);
            s_html += scat("<td>"sv,
                           std::to_string(fpts[pct90_idx]),
                           _I_,
                           std::to_string(spts[pct90_idx]),
                           _I_,
                           std::to_string(bpts[pct90_idx]),
                           _I_,
                           std::to_string(e2es[pct90_idx]),
                           "</td>"sv);
            s_html += scat("<td>"sv,
                           std::to_string(fpts[pct95_idx]),
                           _I_,
                           std::to_string(spts[pct95_idx]),
                           _I_,
                           std::to_string(bpts[pct95_idx]),
                           _I_,
                           std::to_string(e2es[pct95_idx]),
                           "</td>"sv);
            s_html += scat("<td>"sv,
                           std::to_string(fpts[pct99_idx]),
                           _I_,
                           std::to_string(spts[pct99_idx]),
                           _I_,
                           std::to_string(bpts[pct99_idx]),
                           _I_,
                           std::to_string(e2es[pct99_idx]),
                           "</td>"sv);
            s_html += scat("<td>"sv,
                           std::to_string(fpts.back()),
                           _I_,
                           std::to_string(spts.back()),
                           _I_,
                           std::to_string(bpts.back()),
                           _I_,
                           std::to_string(e2es.back()),
                           "</td>"sv);

            s_html += "</tr>"sv;
        }
    }

    s_html += post_html;
    writeTo("/home/liuyaoxin/code/rts_loss40.html"_fp, s_html).get();
}

/*
auto const svr_ep = LocalEndpoint("127.0.0.1"_ip4, Port(8080));

// Echo server handler
Future<> onNewClientConn(TcpSocket tcp_skt, RemoteEndpoint, LocalEndpoint)
{
    auto       buf    = Buffer(16);
    auto const status = co_await tcp_skt.read(buf, 5s);
    if (status > 0)
    {
        co_await tcp_skt.write(MemView(buf.data(), status), 5s);
    }
}

void benchmark()
{
    sleepFor(1s); // Wait for the Echo server to be ready.

    auto success_cnt           = std::atomic_size_t(0);
    auto failure_cnt           = std::atomic_size_t(0);
    auto rtt_less_than_1ms     = std::atomic_size_t(0);
    auto rtt_less_than_2ms     = std::atomic_size_t(0);
    auto rtt_less_than_3ms     = std::atomic_size_t(0);
    auto rtt_less_than_10ms    = std::atomic_size_t(0);
    auto rtt_greater_than_10ms = std::atomic_size_t(0);

    // Send a string to the Echo server and wait for the response.
    auto const fn_tcp_echo_client = [&] -> Future<>
    {
        auto cli_skt = co_await startTcpClient(svr_ep);

        auto stopwatch = Stopwatch{};
        auto status    = co_await cli_skt.write("hello"sv, 5s);

        if (status > 0)
        {
            auto buf = Buffer(16);
            status   = co_await cli_skt.read(buf, 5s);

            auto const elapsed = stopwatch.elapsed();
            if (elapsed < 1ms)
            {
                ++rtt_less_than_1ms;
            }
            else if (elapsed < 2ms)
            {
                ++rtt_less_than_2ms;
            }
            else if (elapsed < 3ms)
            {
                ++rtt_less_than_3ms;
            }
            else if (elapsed < 10ms)
            {
                ++rtt_less_than_10ms;
            }
            else
            {
                ++rtt_greater_than_10ms;
            }

            if (status > 0 && tosv(buf.data(), status) == "hello"sv)
            {
                ++success_cnt;
                co_return;
            }
        }

        ++failure_cnt;
    };

    auto const total_count = 200'000uz;

    // Start millions of clients concurrently.
    LOOP_N (total_count)
    {
        fn_tcp_echo_client();
    }

    while (success_cnt + failure_cnt < total_count)
    {
        sleepFor(10ms);
    }

    xout("Total Count: "sv, total_count);
    xout("Success Count: "sv, success_cnt.load());
    xout("Failure Count: "sv, failure_cnt.load());
    xout("rtt_less_than_1ms: "sv, rtt_less_than_1ms.load());
    xout("rtt_less_than_2ms: "sv, rtt_less_than_2ms.load());
    xout("rtt_less_than_3ms: "sv, rtt_less_than_3ms.load());
    xout("rtt_less_than_10ms: "sv, rtt_less_than_10ms.load());
    xout("rtt_greater_than_10ms: "sv, rtt_greater_than_10ms.load());
}

int main()
{
    try
    {
        IF_CONSTEVAL
        {
            return 0;
        }
        else
        {
            return 1;
        }

        std::expected<int, std::string> s1 = std::unexpected<std::string>(""s);
        s1                                 = 234;
        s1                                 = std::unexpected(""s);
        auto s                             = std::unexpected(12);
        s                                  = std::unexpected(12);
        auto s3 = std::expected<int, std::string>(std::unexpect, ""s);
        auto s4 = std::expected<int, std::string>(std::unexpect);

        auto s5 = s4;

        initPosixEnv();
        createLogThread("/tmp/stx.log"_fp);
        startTcpServer(svr_ep, onNewClientConn);
        std::thread(benchmark).detach();
        startEventLoop("stx"s);
    }
    catch (std::exception const& e)
    {
        LOG_ERROR("Main thread exited: "sv, e.what());
    }
    catch (...)
    {
        LOG_ERROR("Main thread exited abnormally."sv);
    }

    return EXIT_FAILURE;
}
*/